﻿Imports Microsoft.DirectX
Imports Microsoft.DirectX.Direct3D

Class Scene

    Public Shapes As New List(Of Shape)
    Public Camera As Camera
    Public Device As Device

    WriteOnly Property View As FillMode
        Set(ByVal Value As FillMode)
            Device.RenderState.FillMode = Value
        End Set
    End Property

    Private Property Handle As Form

    Public Sub Render(ByVal Width, ByVal Height)
        Camera.Reset()
        AR = Width / Height
        Device.Clear(ClearFlags.Target Or ClearFlags.ZBuffer, Color.SkyBlue, 1, 0)
        SetupMatrices()
        Device.BeginScene()
        Device.RenderState.Ambient = Color.FromArgb(255, 64, 64, 64)
        Dim mat As New Material()
        mat.Ambient = Color.Red
        mat.Diffuse = Color.White
        Device.Material = mat
        For Each Shape In Shapes
            Shape.Draw()
        Next
        Device.SetStreamSource(0, AxisBuffer, 0)
        Device.VertexFormat = CustomVertex.PositionColored.Format
        mat.Ambient = Color.Red
        Device.DrawPrimitives(PrimitiveType.LineList, 0, 84)
        'mat.Ambient = Color.Blue
        'Device.DrawPrimitives(PrimitiveType.LineList, 2, 1)
        Device.EndScene()
        Device.Present()
    End Sub

    Public Sub InitializeGraphics(ByVal Handle As Form)
        Me.Handle = Handle
        PresentParams.Windowed = True
        PresentParams.SwapEffect = SwapEffect.Discard
        PresentParams.EnableAutoDepthStencil = True
        PresentParams.AutoDepthStencilFormat = DepthFormat.D16
        PresentParams.MultiSample = MultiSampleType.None
        For i = 1 To 3
            Try
                Dim DT As DeviceType = Choose(i, DeviceType.Hardware, DeviceType.Hardware, DeviceType.Software)
                Dim CF As CreateFlags = If(i = 1, CreateFlags.HardwareVertexProcessing, CreateFlags.SoftwareVertexProcessing)
                Device = New Device(0, DT, Handle, CF, PresentParams)
                Exit For
            Catch ex As Exception
            End Try
        Next
        Camera = New Camera(Device)
        ResetDevice()
    End Sub

    Dim c As Integer
    Dim AR As Single
    Dim AxisBuffer As VertexBuffer

    Private Sub SetupMatrices()
        Device.Transform.Projection = Matrix.PerspectiveFovLH(Math.PI / 4, AR, 0.1, 1000)
    End Sub

    Function Add(ByVal Shape As Shape) As Shape
        Shapes.Add(Shape)
        Shape.Device = Device
        Return Shape
    End Function

    Property Aliasing As MultiSampleType
        Get
            Return PresentParams.MultiSample
        End Get
        Set(ByVal Value As MultiSampleType)
            PresentParams.MultiSample = Value
            ResetDevice()
        End Set
    End Property

    Dim PresentParams As New PresentParameters

    Public Sub ResetDevice()
        If Device Is Nothing Then Exit Sub
        Device.Reset(PresentParams)
        Device.RenderState.Lighting = True
        Device.RenderState.SpecularEnable = True
        Device.RenderState.ZBufferEnable = True
        Device.RenderState.CullMode = Cull.CounterClockwise
        Device.RenderState.PointSize = 4
        Device.RenderState.FillMode = FillMode.Solid
        For Each Shape In Shapes
            Shape.Device = Device
            Shape.Create()
        Next
        Device.Lights(0).Type = LightType.Directional
        Device.Lights(0).Diffuse = Color.White
        Device.Lights(0).Ambient = Color.Gray
        'Device.Lights(0).Position = New Vector3(2, 80, -1)
        Device.Lights(0).Direction = New Vector3(2, 80, -1)
        Device.Lights(0).Enabled = True

        Device.Lights(0).Type = LightType.Directional
        Device.Lights(0).DiffuseColor = New ColorValue(0, 0, 255)
        Device.Lights(0).AmbientColor = New ColorValue(10, 10, 20)
        Device.Lights(0).Direction = New Vector3(900, 900, -1)
        Device.Lights(0).Enabled = True

        Device.Lights(1).Type = LightType.Directional
        Device.Lights(1).DiffuseColor = New ColorValue(255, 255, 0)
        Device.Lights(1).AmbientColor = New ColorValue(100, 10, 20)
        Device.Lights(1).Direction = New Vector3(0, -900, 0)
        Device.Lights(1).Enabled = True

        AxisBuffer = New VertexBuffer(GetType(CustomVertex.PositionColored), 84, Device, 0, CustomVertex.PositionColored.Format, Pool.Default)
        Dim Vertices As CustomVertex.PositionColored() = CType(AxisBuffer.Lock(0, 0), CustomVertex.PositionColored())
        Dim i As Integer = 0
        For x = -5 To 5 Step 0.5
            Vertices(i) = New CustomVertex.PositionColored(x, 0, -5, Color.White.ToArgb) : i += 1
            Vertices(i) = New CustomVertex.PositionColored(x, 0, 5, Color.White.ToArgb) : i += 1
            Vertices(i) = New CustomVertex.PositionColored(-5, 0, x, Color.White.ToArgb) : i += 1
            Vertices(i) = New CustomVertex.PositionColored(5, 0, x, Color.White.ToArgb) : i += 1
        Next
        'Vertices(0) = New CustomVertex.PositionColored(-1000, 0, 0, Color.White.ToArgb)
        'Vertices(1) = New CustomVertex.PositionColored(1000, 0, 0, Color.Red.ToArgb)
        'Vertices(2) = New CustomVertex.PositionColored(0, -1000, 0, Color.Green.ToArgb)
        'Vertices(3) = New CustomVertex.PositionColored(0, 1000, 0, Color.Green.ToArgb)
        'Vertices(4) = New CustomVertex.PositionColored(0, 0, -1000, Color.Blue.ToArgb)
        'Vertices(5) = New CustomVertex.PositionColored(0, 0, 1000, Color.Blue.ToArgb)
        AxisBuffer.Unlock()
    End Sub

End Class

Class Camera

    Dim fxa, fya
    Dim Device As Device

    Sub New(ByVal Device As Device)
        Me.Device = Device
    End Sub

    Sub Rotate(ByVal rx As Double, ByVal ry As Double)
        fxa += rx * Math.Min(1, ZoomFactor)
        fya += ry * Math.Min(1, ZoomFactor)
        Reset()
    End Sub

    Dim ZoomFactor As Single = 1
    Sub Zoom(ByVal Factor As Single)
        ZoomFactor *= Factor
        CameraLocation = New Vector3(0, 0, -4 * ZoomFactor)
        Reset()
    End Sub

    Property CameraLocation As New Vector3(0, 0, -4)

    Sub Reset()
        Device.Transform.View = Matrix.LookAtLH(CameraLocation, New Vector3(0, 0, 0), New Vector3(0, 1, 0))
        Device.Transform.View = Matrix.RotationY(-fya) * Device.Transform.View
        Dim z = Device.Transform.View
        Dim a As New Vector3(z.M11, z.M21, z.M31)
        Device.Transform.View = Matrix.RotationAxis(a, fxa) * Device.Transform.View
    End Sub

    Sub Offset(ByVal rx As Double, ByVal ry As Double, ByVal rz As Double)
        'For Each Shape In Shapes
        '    Shape.Offset(rx, ry, rz)
        'Next
        'RaiseEvent Invalidate()
        'Eye.Offset(rx, ry, rz)
    End Sub

End Class
